package com.lx.composetest.glpaint

import android.content.Context
import android.graphics.Color
import android.graphics.Paint
import android.opengl.GLES20
import android.opengl.Matrix
import android.os.Build
import android.util.AttributeSet
import android.util.Log
import android.view.InputDevice
import android.view.MotionEvent
import androidx.graphics.lowlatency.BufferInfo
import androidx.graphics.lowlatency.GLFrontBufferedRenderer
import androidx.graphics.opengl.egl.EGLManager
import androidx.input.motionprediction.MotionEventPredictor
import com.chillingvan.canvasgl.ICanvasGL
import com.chillingvan.canvasgl.glcanvas.GLPaint
import com.chillingvan.canvasgl.glview.texture.GLTextureView
import com.lx.composetest.ink.InkRecorder
import com.lx.composetest.lowlatency.LineRenderer.Companion.FragmentShaderCode
import com.lx.composetest.lowlatency.LineRenderer.Companion.VertexShaderCode
import com.lx.composetest.lowlatency.loadShader
import java.util.LinkedList

/**
 *  desc : TODO Fill the fucking desc
 *
 *
 *  @author LuXin
 *  @createTime 2024/7/31
 */
class MyGLCanvasTextureView : GLView {
    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)

    private var mWidth: Int = 0
    private var mHeight: Int = 0
    private var mPreviousX: Float = 0f
    private var mPreviousY: Float = 0f
    private var mCurrentX: Float = 0f
    private var mCurrentY: Float = 0f
    private val LINE = 0f
    private val PREDICT = 1f
    private val motionPredictor = MotionEventPredictor.newInstance(this)
    private var mFrontBufferRenderer: GLFrontBufferedRenderer<FloatArray>? = null
    private val TAG = "MyGLCanvasTextureView"
    private val paint = GLPaint().apply {
        this.color = Color.RED
        this.lineWidth = 10f
        this.style = Paint.Style.STROKE
    }
    private var currentPosition = FloatArray(4)
    private var mGLProgram: Int = 0
    override fun onGLDraw(canvas: ICanvasGL?) {
        Log.i(
            TAG,
            "onGLDraw: ${currentPosition[0]} , ${currentPosition[1]} ,${currentPosition[2]} , ${currentPosition[3]}"
        )
//        if (currentPosition[0] > 0f) {
//            canvas?.drawLine(0f,0f,1000f,1000f,paint)
//        }
        GLES20.glUseProgram(mGLProgram)

        canvas?.drawLine(
            currentPosition[0],
            currentPosition[1],
            currentPosition[2],
            currentPosition[3],
            paint
        )
    }

    init {
        val mVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, VertexShaderCode)
        val mFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, FragmentShaderCode)
        val mGlProgram = GLES20.glCreateProgram()
        GLES20.glAttachShader(mGlProgram, mVertexShader)
        GLES20.glAttachShader(mGlProgram, mFragmentShader)
    }

    private val mCallbacks = object : GLFrontBufferedRenderer.Callback<FloatArray> {
        private val mMVPMatrix = FloatArray(16)
        private val mProjection = FloatArray(16)
        private val mSceneParams = ArrayList<FloatArray>()
        private var previousWipeLine: FloatArray? = FloatArray(5)
        private var previousLine: FloatArray? = FloatArray(5)
        private var previousLineQueue: LinkedList<FloatArray> = LinkedList<FloatArray>()

        override fun onDrawFrontBufferedLayer(
            eglManager: EGLManager,
            bufferWidth: Int,
            bufferHeight: Int,
            bufferInfo: BufferInfo,
            transform: FloatArray,
            param: FloatArray
        ) {
            Log.i(TAG, "onDrawFrontBufferedLayer: ${Thread.currentThread()}")
//            queueEvent {
            currentPosition = param
            onGLDraw(mCanvas)
//            }
            requestRender()
        }

        override fun onDrawMultiBufferedLayer(
            eglManager: EGLManager,
            bufferWidth: Int,
            bufferHeight: Int,
            bufferInfo: BufferInfo,
            transform: FloatArray,
            params: Collection<FloatArray>
        ) {
            Log.i(TAG, "onDrawMultiBufferedLayer: ")
        }
    }

    init {
        mGLProgram = GLES20.glCreateProgram()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            requestUnbufferedDispatch(InputDevice.SOURCE_CLASS_POINTER)
        }
        setOnTouchListener { _, event ->
            motionPredictor.record(event)
            InkRecorder.addNewTouchEvent(event)
            when (event.action) {
                MotionEvent.ACTION_DOWN -> {
                    this.requestUnbufferedDispatch(event)
                    mCurrentX = event.x
                    mCurrentY = event.y
                }

                MotionEvent.ACTION_MOVE -> {
                    mPreviousX = mCurrentX
                    mPreviousY = mCurrentY
                    mCurrentX = event.x
                    mCurrentY = event.y
                    val line = FloatArray(5).apply {
                        this[0] = mPreviousX
                        this[1] = mPreviousY
                        this[2] = mCurrentX
                        this[3] = mCurrentY
                        this[4] = LINE
                    }
                    mFrontBufferRenderer?.renderFrontBufferedLayer(line)
                    Log.i("InkSurfaceView", "orientation :${event.orientation}")

//                    val motionEventPredicted = motionPredictor.predict()
//                    //处理预测点位
//                    if (motionEventPredicted != null) {
//                        //仅仅使用一半的预测
//                        val predictX = mCurrentX + (motionEventPredicted.x - mCurrentX) / 2f
//                        val predictY =  mCurrentY + (motionEventPredicted.y - mCurrentY) / 2f
//                        //预测点位标识：PREDICT
//                        val predictedSegment = floatArrayOf(
//                            mCurrentX, mCurrentY,
//                            predictX,predictY, PREDICT
//                        )
//                        mFrontBufferRenderer?.renderFrontBufferedLayer(predictedSegment)
//                    }
                }

                MotionEvent.ACTION_CANCEL -> {
                    mFrontBufferRenderer?.commit()
                }

                MotionEvent.ACTION_UP -> {
                    mFrontBufferRenderer?.commit()
                }
            }
            true
        }
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        super.onLayout(changed, left, top, right, bottom)
        mWidth = right - left
        mHeight = bottom - top
    }

    override fun onDetachedFromWindow() {
        mFrontBufferRenderer?.release(true) {
        }
        super.onDetachedFromWindow()
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        mFrontBufferRenderer = GLFrontBufferedRenderer(this, mCallbacks)
    }
}